package cn.iocoder.yudao.module.nmkj.service.useraccess;

import cn.iocoder.yudao.module.nmkj.dal.redis.useraccess.UserAccessRedisDAO;
import cn.iocoder.yudao.module.nmkj.utils.ClientIPUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.annotation.Validated;

import cn.iocoder.yudao.module.nmkj.controller.admin.useraccess.vo.*;
import cn.iocoder.yudao.module.nmkj.dal.dataobject.useraccess.UserAccessDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.nmkj.dal.mysql.useraccess.UserAccessMapper;

import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_ACCESS_NOT_EXISTS;

/**
 * 访客消息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class UserAccessServiceImpl implements UserAccessService {

    @Resource
    private UserAccessMapper userAccessMapper;
    @Resource
    UserAccessRedisDAO userAccessRedisDAO;
    @Resource
    ClientIPUtils clientIPUtils;

    private static final int MAX_USER_INSERT_MESSAGE = 5;
    private static final String USER_ACCESS_COOKIE_KEY = "userAccessCookieKey";

    @Override
    public Long createUserAccess(UserAccessSaveReqVO createReqVO) {
        // 插入
        UserAccessDO userAccess = BeanUtils.toBean(createReqVO, UserAccessDO.class);
        userAccessMapper.insert(userAccess);
        // 返回
        return userAccess.getId();
    }

    /*
     * 通过 IP 和 Cookie 双重安全机制对用户发送的消息进行限制判断
     * IP 则是通过 Redis 进行缓存
     * Cookie 由客户端缓存
     */
    @Override
    public Long createUserAccess(UserAccessSaveReqVO createReqVO, HttpServletRequest request, HttpServletResponse response) {
        //获取绝对IP
        String ip = clientIPUtils.getClientIp(request);
        System.out.println("IPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIPIP: " + ip);
        //获取Cookie (如果有)
        AtomicReference<Cookie> atomic = new AtomicReference<>();
        Optional<Cookie> cookiesFilter = Stream.of(request.getCookies()).filter(c -> c.getName().equals(USER_ACCESS_COOKIE_KEY)).findFirst();
        cookiesFilter.ifPresent(atomic::set);
        Cookie cookie = atomic.get();
        //得到 IP 访客发送消息的数量
        Integer userAccessCount = userAccessRedisDAO.get(ip); //这里无需判断 null，返回值一定为 int 类型
        //如果 Cookie null 对 Cookie 设置值
        if (cookie == null) {
            cookie = new Cookie(USER_ACCESS_COOKIE_KEY, String.valueOf(userAccessCount));
        }
        //获取 Cookie 访客发送消息的数量
        int userAccessCountByCookie = Integer.parseInt(cookie.getValue() == null || !cookie.getValue().matches("\\d+") ? "0" : cookie.getValue());
        //通过 cookie 和 ip 判断出最大数量那个进行做参考值
        int maxUserAccessCount = Math.max(userAccessCount, userAccessCountByCookie);
        System.out.println("CookieCookieCookieCookieCookieCookieCookie:  " + cookie.getName() + " ---> " + cookie.getValue());
        if (maxUserAccessCount < MAX_USER_INSERT_MESSAGE) {
            Long code = createUserAccess(createReqVO); //插入
            if (code != null && code > 0) { //更新 Redis
                userAccessRedisDAO.set(ip, maxUserAccessCount + 1);
                //设置返回的 cookie
                cookie.setValue(String.valueOf(maxUserAccessCount + 1));
                response.addCookie(cookie); //添加到响应头
            }
            return code;
        }
        return -1L; //-1错误码，不可插入
    }

    @Override
    public void updateUserAccess(UserAccessSaveReqVO updateReqVO) {
        // 校验存在
        validateUserAccessExists(updateReqVO.getId());
        // 更新
        UserAccessDO updateObj = BeanUtils.toBean(updateReqVO, UserAccessDO.class);
        userAccessMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserAccess(Long id) {
        // 校验存在
        validateUserAccessExists(id);
        // 删除
        userAccessMapper.deleteById(id);
    }

    private void validateUserAccessExists(Long id) {
        if (userAccessMapper.selectById(id) == null) {
            throw exception(USER_ACCESS_NOT_EXISTS);
        }
    }

    @Override
    public UserAccessDO getUserAccess(Long id) {
        return userAccessMapper.selectById(id);
    }

    @Override
    public PageResult<UserAccessDO> getUserAccessPage(UserAccessPageReqVO pageReqVO) {
        return userAccessMapper.selectPage(pageReqVO);
    }

}